#include "viewer.h"
#include <iostream>
#include <algorithm>
#include <vector>


using namespace std;

//Constructor
viewer::viewer()
: road("Road"),
grass("Grass"),
trail("Stony trail"),
start("Start"),
goal("Goal"),
wall("Wall"),
unsortedA("Unsorted vector"),
sortedAByF("Sorted vector by cost"),
sortedAByXY("Sorted vector by X,Y"),
skipL("Skip list"),
hashT("Hash table"),
hashTVector("Hash T + Sorted V"),
rightAlignment(Gtk::ALIGN_RIGHT, Gtk::ALIGN_TOP, 0.11, 1.0),
executeAlignment(Gtk::ALIGN_RIGHT, Gtk::ALIGN_BOTTOM, 0.0, 0.0),
mainBox(false,0)
{

  	//Set some attributes of the window
  	set_border_width(0);
	Glib::RefPtr<Gdk::Screen> screen = Gdk::Screen::get_default();
	int resX = screen->get_width();
	int resY = screen->get_height();
	resize(500, 600);
	set_title("Path Finder Viewer");	
	move(0, 0);

	//Pack the main box into the window
	add(mainBox);

	//Create the menu of the window
	createMenu();

	//Create the results dialog
	rDialogAction = new resultsDialogAction(this);

	//Create the new grid dialog
	nGridAction = new newGridAction(this);
	gData = nGridAction->getGridData();

	//Create the execution controller and set the needed information
	eController = new executionController(this);
	eController->setGridData(gData);
	eController->setResultsDialogAction(rDialogAction);
	
	
	//Get the menu bar and add it to the main box
	Gtk::Widget* menuBar = manager->get_widget("/MenuBar");
	if(menuBar)
	{
		mainBox.pack_start(*menuBar, Gtk::PACK_SHRINK);
	}

	//Add the secondary box to the main box
	mainBox.pack_start(secondaryBox);

	//Divide the secondary box in two horizontal sections
	secondaryBox.pack_start(leftBox);
	secondaryBox.pack_end(rightAlignment, Gtk::PACK_SHRINK);

	//In the left one, add the scrolled window which will contain the grid
	Gtk::ScrolledWindow* scrollW = manage(new Gtk::ScrolledWindow());
	leftBox.pack_start(*scrollW, Gtk::PACK_EXPAND_WIDGET);

	//Set the policies to the scrolled window of the grid
	scrollW->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
	scrollW->set_border_width(7);

	//Add the pointer to the scrolled window in the newGridData structure
	gData->scrollW = scrollW;

	//In the right one, add a vertical box to add on it the radio buttons and the execute button
	rightAlignment.add(rightBox);
	rightAlignment.set_size_request(185,450);

	//Create the radio buttons for choosing cell types, algorithms and data structures
	createRadioButtons();
	
	//Add the execute button in the bottom and the radio buttons box in the top of the right box
	rightBox.pack_start(radioButtonsBox);
	rightBox.pack_start(executeAlignment);
	executeAlignment.add(execute);

	//Set some attributes of the execute button
	execute.set_label("Execute algorithm");
	execute.set_border_width(7);

	//When the execute button is clicked, the function on_button_clicked is called
	execute.signal_clicked().connect(sigc::mem_fun(*this, &viewer::on_button_execute_clicked));

	//When the window is being closed, the function on_window_quit is called
	this->signal_hide().connect(sigc::mem_fun(*this, &viewer::on_window_quit));

  	// The final step is to display this newly created widget...
  	show_all_children();
}


viewer::~viewer()
{
}


//Return the cell radiobutton id that is active
int viewer::getCellButtonActive()
{
	//Obtain which radio button is active
	int activeButton;
	if(road.get_active()) activeButton = Pfv::ROAD_CELL;
	else if(grass.get_active()) activeButton = Pfv::GRASS_CELL;
	else if(trail.get_active()) activeButton = Pfv::TRAIL_CELL;
	else if(wall.get_active()) activeButton = Pfv::WALL_CELL;
	else if(start.get_active()) activeButton = Pfv::START_CELL;
	else activeButton = Pfv::GOAL_CELL;

	return activeButton;
}


//Create the main menu of the window with the File and Help submenus
void viewer::createMenu()
{
	//Create the action group to create the menus
  	actionGroup = Gtk::ActionGroup::create();

	//File menu
	actionGroup->add(Gtk::Action::create("FileMenu", "File"));

	//Sub menu New and Quit
	actionGroup->add(Gtk::Action::create("FileNew",  Gtk::Stock::NEW, "New"),
		sigc::mem_fun(*this, &viewer::on_show_new_dialog));
	actionGroup->add(Gtk::Action::create("FileQuit",  Gtk::Stock::QUIT, "Quit"),
		sigc::mem_fun(*this, &viewer::on_window_quit));


	//Options menu
	actionGroup->add( Gtk::Action::create("OptionsMenu", "Options") );
	actionGroup->add(Gtk::Action::create("ShowInfo", "Show results"),
		sigc::mem_fun(*this, &viewer::on_menu_show_results));
	cellSpacing = Gtk::ToggleAction::create("CellSpacing", "Cell spacing");
	actionGroup->add(cellSpacing,
		    sigc::mem_fun(*this, &viewer::on_menu_cell_spacing) );

	//Create the UIManager and insert into it the menu
	manager = Gtk::UIManager::create();
	manager->insert_action_group(actionGroup);
	add_accel_group(manager->get_accel_group());

	//Layout the actions in a menubar and toolbar:
	Glib::ustring info = 
		"<ui>"
		"  <menubar name='MenuBar'>"
		"    <menu action='FileMenu'>"
		"      <menuitem action='FileNew'/>"
		"      <menuitem action='FileQuit'/>"
		"    </menu>"
		" 	 <menu action='OptionsMenu'>"
		"      <menuitem action='ShowInfo'/>"
		"  	   <menuitem action='CellSpacing'/>"
		" 	 </menu>"
		"  </menubar>"
		"</ui>";

	#ifdef GLIBMM_EXCEPTIONS_ENABLED
	try
	{
		manager->add_ui_from_string(info);
	}
	catch(const Glib::Error& ex)
	{
		Gtk::MessageDialog dialog(*this, "Building menus failed.", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, false);
		dialog.set_secondary_text(ex.what());
		dialog.show();
	}
	#else
	std::auto_ptr<Glib::Error> ex;
	manager->add_ui_from_string(info, ex);
	if(ex.get())
	{
		Gtk::MessageDialog dialog(*this, "Building menus failed.", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, false);
		dialog.set_secondary_text(ex.what());
		dialog.show();
	}
	#endif
}


//Create 3 frames at the right of the window that include the radio buttons needed to choose
//the cell type, algorithm and data structure
void viewer::createRadioButtons()
{
	//Add 3 frames in the radio buttons box which will contain the cell, algorithm and data radio buttons
	radioButtonsBox.pack_start(cellTypesFrame);
	radioButtonsBox.pack_start(dataFrame);
	cellTypesFrame.set_border_width(7);
	dataFrame.set_border_width(7);

	//Set the name of the frames
	cellTypesFrame.set_label("Cell type");
	dataFrame.set_label("Data structure");

	//Add a box in each radio button frame
	cellTypesFrame.add(cellTypesBox);
	dataFrame.add(dataBox);

	//Add each cell radio button in the same group
	cellTypes = road.get_group();
	road.set_border_width(1);
	grass.set_group(cellTypes);
	grass.set_border_width(1);
	trail.set_group(cellTypes);
	trail.set_border_width(1);
	start.set_group(cellTypes);
	start.set_border_width(1);
	goal.set_group(cellTypes);
	goal.set_border_width(1);
	wall.set_group(cellTypes);
	wall.set_border_width(1);

	//Initially activate the normal cell radio button
	start.set_active();

	//Add each data structure radio button in the same group
	data = unsortedA.get_group();
	unsortedA.set_border_width(1);
	sortedAByF.set_group(data);
	sortedAByF.set_border_width(1);
	sortedAByXY.set_group(data);
	sortedAByXY.set_border_width(1);
	skipL.set_group(data);
	skipL.set_border_width(1);
	hashT.set_group(data);
	hashT.set_border_width(1);
	hashTVector.set_group(data);
	hashTVector.set_border_width(1);

	//Initially activate the unsorted vector radio button
	unsortedA.set_active();

	//Add the cell radio buttons to the cells box
	cellTypesBox.pack_start(road);
	cellTypesBox.pack_start(grass);
	cellTypesBox.pack_start(trail);
	cellTypesBox.pack_start(start);
	cellTypesBox.pack_start(goal);
	cellTypesBox.pack_start(wall);

	//Add the data radio buttons to the data box
	dataBox.pack_start(unsortedA);
	dataBox.pack_start(sortedAByF);
	dataBox.pack_start(sortedAByXY);
	dataBox.pack_start(skipL);
	dataBox.pack_start(hashT);
	dataBox.pack_start(hashTVector);
}



//Show a dialog containing the tree with the results of the algorithms executed
void viewer::on_menu_show_results()
{
	rDialogAction->showResultsDialog();
}


//If the cell spacing check button has been activated, this function creates a little spacing 
//between the cells of the grid. Otherwise, it removes that spacing
void viewer::on_menu_cell_spacing()
{
	modifyGridAction::modifyCellSpacing();
}


//Signal handler activated when the user has clicked the Execute algorithm button
void viewer::on_button_execute_clicked()
{
	int structure;
	if(unsortedA.get_active()) structure = UNSORTED_VECTOR;
	else if(sortedAByF.get_active()) structure = SORTED_VECTOR_BY_F;
	else if(sortedAByXY.get_active()) structure = SORTED_VECTOR_BY_XY;
	else if(skipL.get_active()) structure = SKIP_LIST;
	else if(hashT.get_active()) structure = HASH_TABLE;
	else structure = HASH_TABLE_VECTOR;

	eController->execute(structure);
}


//Signal handler activated when the user press the Quit button
void viewer::on_window_quit()
{
	//Free memory
	nGridAction->freeMemory();
	nGridAction->~newGridAction();
	rDialogAction->~resultsDialogAction();
	eController->freeMemory();
	eController->~executionController();

	//Close the window
	hide();
}

void viewer::on_show_new_dialog()
{
	nGridAction->showNewDialog();
}